<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Example: Post Office
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora177.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora179.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Example: Post Office</H2><A NAME="sec-poste"></A>
We present, to end this chapter, a slightly more complete example of a
concurrent program: modelling a common queue at a number of counters
at a post office.<BR>
<BR>
As always in concurrent programming the problems are posed
metaphorically, but replace the counters of the post office by a
collection of printers and you have the solution to a genuine problem
in computing.<BR>
<BR>
Here the policy of service that we propose; it is well tried and tested,
rather than original: each client takes a number when he
arrives; when a clerk has finished serving a client, he calls for a
number. When his number is called, the client goes to the
corresponding counter.<BR>
<BR>

<H5> Organization of development.</H5>
We distinguish in our development <EM>resources</EM>, and <EM>agents</EM>.
The former are: the number dispenser, the number announcer,
and the windows. The latter are: the clerks and the clients. The
resources are modeled by objects which manage their own mutual exclusion
mechanisms. The agents are modelled by
functions executed by a thread. When an agent wishes to modify or examine
the state of an object, it does not itself have to know about or
manipulate mutexes, which allows a simplified organization for access to sensitive data, 
and avoids oversights in the coding of the agents.<BR>
<BR>
<A NAME="toc266"></A>
<H3> The Components</H3>

<H5> The Dispenser.</H5>
The number dispenser contains two fields: a counter and a mutex. The
only method provided by the distributor is the taking of a new number.<BR>
<BR>


<PRE><BR># <B>class</B><CODE> </CODE>dispenser<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Mutex.create()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>take<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Mutex.lock<CODE> </CODE>m<CODE> </CODE>;<CODE> </CODE>n<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>n<CODE>+</CODE><CODE>1</CODE><CODE> </CODE>;<CODE> </CODE>n<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Mutex.unlock<CODE> </CODE>m<CODE> </CODE>;<CODE> </CODE>r<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class dispenser :</CODE><BR><CODE>  unit -&gt;</CODE><BR><CODE>  object val m : Mutex.t val mutable n : int method take : unit -&gt; int end</CODE><BR>

</PRE>

The mutex prevents two clients from taking a number at the same time.
Note the way in which we use an intermediate variable (<TT>r</TT>) to
guarantee that the number calculated in the critical section is the
same as the one return by the method call.<BR>
<BR>

<H5> The Announcer.</H5>
The announcer contains three fields: an integer (the client number
being called); a mutex and a condition variable. The two methods
are: (<TT>wait</TT>) which reads the number, and (<TT>call</TT>),
which modifies it.<BR>
<BR>


<PRE><BR># <B>class</B><CODE> </CODE>announcer<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>nclient<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Mutex.create()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Condition.create()<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>wait<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.lock<CODE> </CODE>m;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE>n<CODE> </CODE><CODE>&gt;</CODE><CODE> </CODE>nclient<CODE> </CODE><B>do</B><CODE> </CODE>Condition.wait<CODE> </CODE>c<CODE> </CODE>m<CODE> </CODE><B>done</B>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.unlock<CODE> </CODE>m;<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>call<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Mutex.lock<CODE> </CODE>m<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>nclient<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>nclient<CODE>+</CODE><CODE>1</CODE><CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>nclient<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Condition.broadcast<CODE> </CODE>c<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.unlock<CODE> </CODE>m<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>r<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>

The condition variable is used to put the clients to sleep, waiting
for their number. They are all woken up when the method <TT>call</TT> is
invoked. Reading or writing access to the called number is protected
by the mutex.<BR>
<BR>

<H5> The window.</H5>
The window consists of five fields: a fixed window number (variable
<TT>ncounter</TT>); the number of the client being waited for
(variable <TT>nclient</TT>); a boolean (variable
<TT>available</TT>); a mutex, and a condition variable.<BR>
<BR>
It offers eight methods, of which two are private: two simple access
methods (methods <TT>get_ncounter</TT> and <TT>get_nclient</TT>): a
group of three methods simulating the waiting period of the clerk
between two clients (private method <TT>wait</TT> and public methods
<TT>await_arrival</TT>, <TT>await_departure</TT>); a group of three
methods simulate the occupation of the window (private method
<TT>set_available</TT> and methods <TT>arrive</TT>, <TT>depart</TT>).<BR>
<BR>


<PRE><BR># <B>class</B><CODE> </CODE>counter<CODE> </CODE><TT>(</TT>i<CODE>:</CODE>int<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>ncounter<CODE> </CODE><CODE>=</CODE><CODE> </CODE>i<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>nclient<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>available<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>true</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Mutex.create()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Condition.create()<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_ncounter<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ncounter<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_nclient<CODE> </CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE>nclient<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>private</B><CODE> </CODE>wait<CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.lock<CODE> </CODE>m<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE>f<CODE> </CODE>()<CODE> </CODE><B>do</B><CODE> </CODE>Condition.wait<CODE> </CODE>c<CODE> </CODE>m<CODE> </CODE><B>done</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.unlock<CODE> </CODE>m<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>wait_arrival<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>nclient<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>n<CODE> </CODE>;<CODE> </CODE>self#wait<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>()<CODE> </CODE>-&gt;<CODE> </CODE>available<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>wait_departure<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE>self#wait<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>()<CODE> </CODE>-&gt;<CODE> </CODE>not<CODE> </CODE>available<TT>)</TT><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>private</B><CODE> </CODE>set_available<CODE> </CODE>b<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.lock<CODE> </CODE>m<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>available<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>b<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Condition.signal<CODE> </CODE>c<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Mutex.unlock<CODE> </CODE>m<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>arrive<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>self#set_available<CODE> </CODE><B>false</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>leave<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>self#set_available<CODE> </CODE><B>true</B><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>

<H5> A post office.</H5>
We collect these three resources in a record type:<BR>
<BR>


<PRE><BR># <B>type</B><CODE> </CODE>office<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>d<CODE> </CODE><CODE>:</CODE><CODE> </CODE>dispenser<CODE> </CODE>;<CODE> </CODE>a<CODE> </CODE><CODE>:</CODE><CODE> </CODE>announcer<CODE> </CODE>;<CODE> </CODE><CODE> </CODE>cs<CODE> </CODE><CODE>:</CODE><CODE> </CODE>counter<CODE> </CODE>array<CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
<A NAME="toc267"></A>
<H3> Clients and Clerks</H3>
The behaviour of the system as a whole will depend on the three
following parameters:


<PRE><BR># <B>let</B><CODE> </CODE>service_delay<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>1</CODE><CODE>.</CODE><CODE>7</CODE><CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>arrival_delay<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>1</CODE><CODE>.</CODE><CODE>7</CODE><CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>counter_delay<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><CODE>.</CODE><CODE>5</CODE><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
Each represents the maximum value of the range from which each
effective value will be randomly chosen. The first parameter models
the time taken to serve a client; the second, the delay between the
arrival of clients in the post office; the last, the time it
takes a clerk to call a new client after the last one has left.<BR>
<BR>

<H5> The Clerk.</H5>
The work of a clerk consists of looping indefinitely over the
following sequence:
<OL type=1>
<LI>
 Call for a number.

<LI> Wait for the arrival of a client holding the called number.

<LI> Wait for the departure of the client occupying his counter.
</OL>Adding some output, we get the function:


<PRE><BR># <B>let</B><CODE> </CODE>clerk<CODE> </CODE><TT>(</TT><TT>(</TT>a<CODE>:</CODE>announcer<TT>)</TT><CODE>,</CODE><CODE> </CODE><TT>(</TT>c<CODE>:</CODE>counter<TT>)</TT><TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>a#call<CODE> </CODE>()<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Counter %d calls %d\n"</CODE><CODE> </CODE>c#get_ncounter<CODE> </CODE>n<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>c#wait_arrival<CODE> </CODE>n<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>c#wait_departure<CODE> </CODE>()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Thread.delay<CODE> </CODE><TT>(</TT>Random.float<CODE> </CODE>counter_delay<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><CODE> </CODE>;;<BR><CODE>val clerk : announcer * counter -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> The Client.</H5>
A client executes the following sequence:
<OL type=1>
<LI>
 Take a waiting number.

<LI> Wait until his number is called.

<LI> Go to the window having called for the number to obtain service.
</OL>
The only slightly complex activity of the client is to find the counter
where they are expected.<BR>
<BR>
We give, for this, the auxiliary function:


<PRE><BR># <B>let</B><CODE> </CODE>find_counter<CODE> </CODE>n<CODE> </CODE>cs<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>0</CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>while</B><CODE> </CODE>cs<CODE>.</CODE><TT>(</TT><CODE>!</CODE>i<TT>)</TT>#get_ncounter<CODE> </CODE><CODE>&lt;&gt;</CODE><CODE> </CODE>n<CODE> </CODE><B>do</B><CODE> </CODE>incr<CODE> </CODE>i<CODE> </CODE><B>done</B><CODE> </CODE>;<CODE> </CODE><CODE>!</CODE>i<CODE> </CODE>;;<BR><CODE>val find_counter : 'a -&gt; &lt; get_ncounter : 'a; .. &gt; array -&gt; int = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Adding some output, the principal function of the client is:


<PRE><BR># <B>let</B><CODE> </CODE>client<CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>o<CODE>.</CODE>d#take()<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Arrival of client %d\n"</CODE><CODE> </CODE>n<CODE> </CODE>;<CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>o<CODE>.</CODE>a#wait<CODE> </CODE>n<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ic<CODE> </CODE><CODE>=</CODE><CODE> </CODE>find_counter<CODE> </CODE>n<CODE> </CODE>o<CODE>.</CODE>cs<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>o<CODE>.</CODE>cs<CODE>.</CODE><TT>(</TT>ic<TT>)</TT>#arrive<CODE> </CODE>()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Client %d occupies window %d\n"</CODE><CODE> </CODE>n<CODE> </CODE>ic<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Thread.delay<CODE> </CODE><TT>(</TT>Random.float<CODE> </CODE>service_delay<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>o<CODE>.</CODE>cs<CODE>.</CODE><TT>(</TT>ic<TT>)</TT>#leave<CODE> </CODE>()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"Client %d leaves\n"</CODE><CODE> </CODE>n<CODE> </CODE>;<CODE> </CODE>flush<CODE> </CODE>stdout<CODE> </CODE>;;<BR><CODE>val client : office -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="toc268"></A>
<H3> The System</H3>
The main programme of the application creates a post office and
its clerks (each clerk is a process) then launches a process which
creates an infinite stream of clients (each client is also a process).<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>main<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>{<CODE> </CODE>d<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>dispenser();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>a<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>announcer();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>cs<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><B>let</B><CODE> </CODE>cs0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Array.create<CODE> </CODE><CODE>5</CODE><CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>counter<CODE> </CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE><CODE>4</CODE><CODE> </CODE><B>do</B><CODE> </CODE>cs0<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>new</B><CODE> </CODE>counter<CODE> </CODE>i<CODE> </CODE><B>done</B>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>cs0<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE><CODE>4</CODE><CODE> </CODE><B>do</B><CODE> </CODE>ignore<CODE> </CODE><TT>(</TT>Thread.create<CODE> </CODE>clerk<CODE> </CODE><TT>(</TT>o<CODE>.</CODE>a<CODE>,</CODE><CODE> </CODE>o<CODE>.</CODE>cs<CODE>.</CODE><TT>(</TT>i<TT>)</TT><TT>)</TT><TT>)</TT><CODE> </CODE><B>done</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>create_clients<CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>ignore<CODE> </CODE><TT>(</TT>Thread.create<CODE> </CODE>client<CODE> </CODE>o<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Thread.delay<CODE> </CODE><TT>(</TT>Random.float<CODE> </CODE>arrival_delay<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>ignore<CODE> </CODE><TT>(</TT>Thread.create<CODE> </CODE>create_clients<CODE> </CODE>o<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Thread.sleep<CODE> </CODE>()<CODE> </CODE>;;<BR><CODE>val main : unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>

The last instruction puts the process associated with the program to
sleep in order to pass control immediately to the other active
processes of the application.<BR>
<BR>
<BR>
<BR>

 <BR>
<BR>
 <BR>
<BR>
<HR>
<A HREF="book-ora177.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora179.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
